using System;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Meta;

namespace MetaWorld
{

	/// <summary>
	/// This class provides mapping between DirectX 3D vectors
	/// and Meta's dispatcher for primitive vector space operations.
	/// </summary>
	public class Vector3Space : VectorSpace 
	{
		/// <summary>
		/// Registers operations over 3D vectors with Meta.
		/// </summary>
		public static void RegisterSelf ()
		{
			Register(typeof(Vector3), new Vector3Space()); 
		}

		/// <summary>
		/// Creates a 3D vector from three scalar components.
		/// </summary>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <param name="z"></param>
		/// <returns></returns>
		public static Vector3 MakeVector3 (double x, double y, double z)
		{
			return new Vector3 ((float) x, (float) y, (float) z);
		}

		/// <summary>
		/// Cast the object to vector type.
		/// </summary>
		/// <param name="o"></param>
		/// <param name="operation"></param>
		/// <returns></returns>
		public static Vector3 ToVector3 (object o, string operation) 
		{
			if (o is Vector3)
				return (Vector3)o;
			else 
			{
				CantDo(operation, o);
				return new Vector3 (0f, 0f, 0f);
			}
		}

		/// <summary>
		/// Checks the vectors for equality.
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public override bool CheckEquality (object a, object b) 
		{
			Vector3 va = (Vector3) a;
			Vector3 vb = ToVector3 (b, "equality");

			return (va.X == vb.X && va.Y == vb.Y && va.Z == vb.Z);
		}

		/// <summary>
		/// Returns the sum of the two vectors.
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public override object Sum (object a, object b) 
		{
			Vector3 va = (Vector3) a;
			Vector3 vb = ToVector3 (b, "addition");

			return Vector3.Add (va, vb);
		}

		/// <summary>
		/// Returns the difference of the two vectors.
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public override object Difference (object a, object b) 
		{
			Vector3 va = (Vector3) a;
			Vector3 vb = ToVector3 (b, "subtraction");

			return Vector3.Subtract (va, vb);
		}

		/// <summary>
		/// Returns the inverted vector.
		/// </summary>
		/// <param name="a"></param>
		/// <returns></returns>
		public override object Negation (object a) 
		{
			Vector3 va = (Vector3) a;

			return Vector3.Scale (va, -1f);
		}

		/// <summary>
		/// Returns the vector multiplied by a scalar.
		/// </summary>
		/// <param name="s"></param>
		/// <param name="a"></param>
		/// <returns></returns>
		public override object ScalarMultiple (double s, object a) 
		{
			Vector3 va = (Vector3) a;

			return Vector3.Multiply (va, (float) s);
		}

		/// <summary>
		/// Returns the dot product of the two vectors.
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public override double InnerProduct (object a, object b) 
		{
			Vector3 va = (Vector3) a;
			Vector3 vb = ToVector3 (b, "inner product");

			return Vector3.Dot (va, vb);
		}

		/// <summary>
		/// Returns the magnitude of the vector.
		/// </summary>
		/// <param name="a"></param>
		/// <returns></returns>
		public override double Norm (object a) 
		{
			Vector3 va = ToVector3 (a, "magnitude");
			return (double) va.Length ();
		}

		/// <summary>
		/// Returns a unit vector for the input.
		/// </summary>
		/// <param name="a"></param>
		/// <returns></returns>
		public override object Unit (object a) 
		{
			Vector3 va = (Vector3) a;
			va.Normalize ();
			return va;
		}

	}

}
